package com.matthicks.delegates.util;

import java.lang.ref.WeakReference;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;

import com.matthicks.delegates.Delegate;
import com.matthicks.delegates.MethodDelegate;

public class ScopeMonitor {
	public static final Delegate MONITOR = MethodDelegate.create(ScopeMonitor.class, "monitorThread");
	
	private static long delay = 100;
	private static Queue<ScopeMonitor> monitors;
	
	private WeakReference<Object> reference;
	private Delegate delegate;
	
	private ScopeMonitor(Object obj, Delegate delegate) {
		reference = new WeakReference<Object>(obj);
		this.delegate = delegate;
	}
	
	public boolean update() {
		if (reference.get() != null) {
			return false;
		}
		try {
			delegate.invoke();
		} catch(Throwable t) {
			t.printStackTrace();
		}
		return true;
	}
	
	public static final synchronized void monitor(Object obj, Delegate delegate) {
		if (monitors == null) {
			monitors = new ConcurrentLinkedQueue<ScopeMonitor>();
		}
		
		ScopeMonitor monitor = new ScopeMonitor(obj, delegate);
		monitors.add(monitor);
	}
	
	// Runs the monitoring system updates
	@SuppressWarnings("unused")
	private static final synchronized void monitorThread() throws InterruptedException {
		while (true) {
			for (ScopeMonitor m : monitors) {
				if (m.update()) {
					// Out of scope, we can remove from the list
					monitors.remove(m);
				}
			}
			Thread.sleep(delay);
		}
	}
	
	public static final void setDelay(long delay, TimeUnit unit) {
		ScopeMonitor.delay = TimeUnit.NANOSECONDS.convert(delay, unit);
	}
}
